using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Runtime.Design;
using System.Xml;
using System.Runtime.InteropServices;
using System.Collections;



namespace SSIS.Tasks
{
    
    [
     Guid("cf241e60-eb1a-4eba-a4a7-bc8f20df1bef"),
     DtsTask(DisplayName = "ExecPackageTask",
             Description = "Executes packages and gets and sets variable values",
             TaskType = "MonkeyOnAUniCycle",
             IconResource = "monkey.ico",
             UITypeName = "SSIS.Tasks.ExecPackageTaskUI,SSIS.Tasks,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=6162700a52442438"
        )]                                                                                                                                                                                                                                    
    
    public class ExecPackageTask : Task, IDTSComponentPersist
        
    {
        
        public ExecPackageTask()
        {
            mappings = new mappingCollection();

        }


        private mappingCollection mappings;
        public mappingCollection Mappings
        {
            get { return mappings;  }
            set { mappings = value; }
        }

        private string pkgPath="";
        public string PackagePath
        {
            get { return pkgPath; }
            set { pkgPath = value; }
        }

        private string pkgLocation;
        public string PackageLocation
        {
            get {return pkgLocation; }
            set {pkgLocation=value; }
        }

        public override DTSExecResult
            Execute(Connections connections,
            VariableDispenser variableDispenser,
            IDTSComponentEvents componentEvents,
            IDTSLogging log,
            object transaction)
        {
            DTSExecResult result = new DTSExecResult();
            try
            {
                Application app = new Application();
                Package pkg;
                //Get Package
                if (PackageLocation.CompareTo("File System") == 0)
                {
                    //Load Package from file system
                    pkg = app.LoadPackage(PackagePath, null);
                }
                else
                {
                    //Load Package from server
                    string serverName = PackagePath.Substring(0, PackagePath.IndexOf("\\"));
                    string packageName = "MSDB\\" + PackagePath.Substring(serverName.Length + 1);
                    pkg = app.LoadFromDtsServer(packageName, serverName, null);
                }
                //Map variable values
                Variables vars = null;

                foreach (mappingCollection.mappingRecord mapping in Mappings)
                {
                    if (mapping.MappingType.CompareTo("Variable") == 0)
                    {
                        string targetVar = mapping.TargetObject.Substring(mapping.TargetObject.IndexOf("::")).Replace("::", "");
                        string sourceVar = mapping.SourceObject.Substring(mapping.SourceObject.IndexOf("::")).Replace("::", "");

                        variableDispenser.LockForWrite(mapping.SourceObject);

                        variableDispenser.GetVariables(ref vars);

                        //Only set value if Mapping Direction is set to Write or Read & Write
                        if (mapping.MappingDirection.Contains("Write") == true)
                        {
                            pkg.Variables[targetVar].Value = vars[sourceVar].Value;
                        }
                    }
                }

                //Map Connections
                foreach (mappingCollection.mappingRecord mapping in Mappings)
                {
                    if (mapping.MappingType.CompareTo("Connection") == 0)
                    {
                        pkg.Connections[mapping.TargetObject].ConnectionString = connections[mapping.SourceObject].ConnectionString;
                    }
                }
                
                //Execute Package
                result = pkg.Execute();

                //Get return values
                foreach (mappingCollection.mappingRecord mapping in Mappings)
                {
                    if (mapping.MappingType.CompareTo("Variable") == 0)
                    {
                        string targetVar = mapping.TargetObject.Substring(mapping.TargetObject.IndexOf("::")).Replace("::", "");
                        string sourceVar = mapping.SourceObject.Substring(mapping.SourceObject.IndexOf("::")).Replace("::", "");
                        if (mapping.MappingDirection.Contains("Read") == true)
                        {
                            vars[sourceVar].Value = pkg.Variables[targetVar].Value;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.StackTrace);
                result = DTSExecResult.Failure;
            }
            
            return result;


        }

        public override DTSExecResult Validate(
            Connections connections,
            VariableDispenser variableDispenser,
            IDTSComponentEvents componentEvents,
            IDTSLogging log)
        {

            //TODO add property validation

            return base.Validate(connections, variableDispenser, componentEvents, log);
        }

        void IDTSComponentPersist.LoadFromXML(System.Xml.XmlElement node, IDTSInfoEvents infoEvents)
        {
            //    This might occur if the task's XML has been modified outside of the Business Intelligence
            //    Or SQL Server Workbenches.

            if (node.Name != "ExecutePkg")
            {
                throw new Exception(string.Format("Unexpected task element when loading task - {0}.", "ExecPkgTask"));
            }
            else
            {
                // let error bubble up
                // populate the private property variables with values from the DTS node.
                this.PackagePath = node.Attributes.GetNamedItem("PackagePath").Value;
                this.PackageLocation = node.Attributes.GetNamedItem("PackageLocation").Value;
                XmlNodeList nl = node.GetElementsByTagName("Mappings");
                Mappings.Clear();
                foreach (XmlNode n in nl)
                foreach (XmlElement m in n.ChildNodes)
                {
                    if (m.Name.CompareTo("Mapping") == 0)
                    {
                        mappingCollection.mappingRecord mapping = new mappingCollection.mappingRecord();
                        mapping.TargetObject = m.Attributes.GetNamedItem("TargetObject").Value.ToString();
                        mapping.SourceObject = m.Attributes.GetNamedItem("SourceObject").Value.ToString();
                        mapping.MappingDirection = m.Attributes.GetNamedItem("MappingDirection").Value.ToString();
                        mapping.MappingType = m.Attributes.GetNamedItem("MappingType").Value.ToString();
                        Mappings.Add(mapping);
                    }
                }
            }
        }


        void IDTSComponentPersist.SaveToXML(System.Xml.XmlDocument doc, IDTSInfoEvents infoEvents)
        {
            //create node in the package xml document
            XmlElement taskElement = doc.CreateElement(string.Empty, "ExecutePkg", string.Empty);

            //    Package Name property
            XmlAttribute pkgPathAttribute = doc.CreateAttribute(string.Empty, "PackagePath", string.Empty);
            pkgPathAttribute.Value = this.PackagePath;
            taskElement.Attributes.Append(pkgPathAttribute);
            XmlAttribute pkgLocationAttribute = doc.CreateAttribute(string.Empty, "PackageLocation", string.Empty);
            pkgLocationAttribute.Value = this.PackageLocation; 
            taskElement.Attributes.Append(pkgLocationAttribute);

            XmlElement e = doc.CreateElement("Mappings");
            taskElement.AppendChild(e);

            foreach (mappingCollection.mappingRecord mr in Mappings)
            {
                XmlElement m = doc.CreateElement("Mapping");
                XmlAttribute a = doc.CreateAttribute("TargetObject");
                a.Value = mr.TargetObject;
                m.Attributes.Append(a);
                a = doc.CreateAttribute("SourceObject");
                a.Value = mr.SourceObject;
                m.Attributes.Append(a);
                e.AppendChild(m);
                a = doc.CreateAttribute("MappingDirection");
                a.Value = mr.MappingDirection;
                m.Attributes.Append(a);
                e.AppendChild(m);
                a = doc.CreateAttribute("MappingType");
                a.Value = mr.MappingType;
                m.Attributes.Append(a);
                e.AppendChild(m);
            }
          
            //add the new element to the package document
            doc.AppendChild(taskElement);
        }
        
    }

        public class ExecPackageTaskUI : IDtsTaskUI
        {
            #region // Fields
            private TaskHost _taskHost;
            private IDtsConnectionService cnnService;
            private Connections connections;

            #endregion
            #region IDtsTaskUI Members

            public void Delete(System.Windows.Forms.IWin32Window parentWindow)
            {
                // Do nothing for this project
            }

            public System.Windows.Forms.ContainerControl GetView()
            {
                return new ExecPackageTaskUIForm(_taskHost, connections);
            }

            public void Initialize(TaskHost taskHost, IServiceProvider serviceProvider)
            {
                
                _taskHost = taskHost;
                cnnService = (IDtsConnectionService)serviceProvider.GetService(typeof(IDtsConnectionService));
                connections = cnnService.GetConnections();
            }

            public void New(System.Windows.Forms.IWin32Window parentWindow)
            {
                // Do nothing for this project
            }

            #endregion
        }

    public class mappingCollection : CollectionBase
    {
        public struct mappingRecord
        {
            private string targetObject;
            public string TargetObject
            {
                get { return targetObject; }
                set { targetObject = value; }
            }
            private string sourceObject;
            public string SourceObject
            {
                get { return sourceObject; }
                set { sourceObject = value; }
            }
            private string mappingDirection;
            public string MappingDirection
            {
                get { return mappingDirection; }
                set { mappingDirection = value; }
            }
            private string mappingType;
            public string MappingType
            {
                get { return mappingType; }
                set { mappingType = value; }
            }
        }

        public virtual void Add(mappingRecord mapping)
        {
            List.Add(mapping);
        }

        public virtual mappingRecord this[int Index]
        {
            get { return (mappingRecord)List[Index]; }
        }
    }
    
}
